Beginners Programming
Round Bitmap Buttons
In a recent series of message threads on the Liberty Basic Conforums site, there has been some discussion around how to get round buttons. The challenge has been to have button like behavior, yet be able to see the background behind the button. It is of cource possible to create a round graphic and use a BMPBUTTON, but the button is square, and the edges of the button, although not part of the round graphic obstruct the view of the background. This is not a problem if the background is solid, but that is rare in a game.
The solution would be to emulate a button, perhaps with a Sprite. Several solutions were suggested, but they all had limitations. Most used the timer, and the limitation of one timer made it difficult to integrate both game events and button management.
Gordon observered -
"To emulate a button, your button should:
Working with sprites is possible but hard to program my only timer for it. It would be great if I could draw a common rectangular button but create a circular space around it where the background shows."
Ken Lewis, Sr. to the rescue. Ken posted some code that shows how to create real buttons that are round and have a bitmap image imposed on them, yet let the background show through the edges. They act like real buttons, because the are real buttons.
The genius to the code is several API calls. Ken says about the snippet of code:
"This snippet was originally posted by Alyce Watson, and was updated by me." As he desribes the operation: "This routine shows how to make round buttons in LB."…" It includes 1 bitmap, and creates 3 buttons using api. You can easily change the loadbmp commands for your own bitmaps".
With Ken and Alyce's gracious consent, I am including the code here for people to use in their own projects. The code and a sample bitmap are included in a zip file called 1rndbttn.zip which is part of the newsletter archive.
'shaped button demo, May 15, 1998
'Alyce Watson <awatson@wctc.net>
'Updated to win32, Dec 10, 2003
'by Ken Lewis, Sr. <kenlewissr@sbcglobal.net>
'comments by Brad Moore
'define an array to hold the region handles once we get them
'there will only be three regions in this example
dim region(3)
'Setup our window
nomainwin
WindowWidth=400
WindowHeight=400
UpperLeftX=int((DisplayWidth-WindowWidth)/2)
UpperLeftY=int((DisplayHeight-WindowHeight)/2)
open "Shaped Buttons" for graphics_nsb_nf as #1
print #1, "trapclose [quit]"
print #1, "down;fill black;flush;redraw"
'set up a trap for the left mouse button down and up conditions
'which occur during a click.
print #1, "setfocus; when leftButtonDown [check.mouse]"
print #1, "when leftButtonUp [button.up]"
'get the system (windows) handle of the LB Window
h=hwnd(#1)
'Get the handle of the DC (Drawing Context)
calldll #user32, "GetDC",_
h as long,_
hDC as long
'Load the bitmap we will be using. It is a 50x50 circle.
loadbmp "ferry","ferry.bmp" '50x50 circle
loadbmp "rose","ferry.bmp" '
loadbmp "blossom","ferry.bmp" '
'Call the function CreateRegion for each of the three bitmaps
'CreateRegion will return the region handle for each region it creates
'We store that handle in the array regnCount()
for regnCount=1 to 3
region(regnCount)=CreateRegion(regnCount)
next regnCount
'Actually put the bitmaps on the window and flush them so they stick.
print #1, "drawbmp ferry 50 50"
print #1, "drawbmp rose 150 150"
print #1, "drawbmp blossom 250 250"
print #1, "flush"
'wait for an event.
wait
[quit]'******************************************
close #1
end
[check.mouse]'******************************************
'this is the down left button event handler - get the mouse coordinates
X=MouseX
Y=MouseY
'check the coordinates against the known areas of the regions we setup
'do this by calling the function regionPoint which returns a zero if
'the coordinants are outside of the region or a non-zero if the are in a region
for checkPoint=1 to 3
if regionPoint(checkPoint,X,Y) then regnPoint=checkPoint
next checkPoint
'we put the array index of the region that tested non-zero (if any) into
'regnPoint. if it is non-zero, then use the GDI32 call to invert the region
if regnPoint then
'save the valid region index so we can use it in the up mouse event too
buttonRegion=region(regnPoint)
calldll #gdi32, "InvertRgn",_
hDC as long,_
buttonRegion as long,_
r as long
'reset the rernPoint index value for our next pass at processing
regnPoint=0
end if
'wait for another event - Or maybe do something differnt
wait
[button.up]'******************************************
'This is where we process the up left mouse button event. This will call
'the DGI32 Invert Region again to invert the inverted region back to normal.
'That makes it look like the button has been released.
if buttonRegion then
calldll #gdi32, "InvertRgn",_
hDC as long,_
buttonRegion as long,_
r as long
'this is where I would process the rest of the code associated with the
'click of this button. Now the button has been pressed and released.
'Don't forget to set the region index value back to zero here...
buttonRegion=0
end if
wait
'------------------ The support Functions -------------------------------
'This is the Create Region function. It creates a region for the area
'specified. In this case the area is calculated knowing the size of the
'bmp and the location based on the button count we are processing. You might
'have your values preloaded into an array maybe. The GDI32 function requires
'the bounding coordinates of the ellipse - they are in the variables uLx, uLy,
'lRx and lRy. The function returns the handle of the region created.
Function CreateRegion(count)
uLx=(50*count)+(50*(count-1))
uLy=uLx
lRx=uLx+100
lRy=uLy+100
calldll #gdi32, "CreateEllipticRgn",_
uLx as long,_ 'upperleftX
uLy as long,_ 'upperleftY
lRx as long,_ 'lowerrightX
lRy as long,_ 'lowerrightY
CreateRegion as long
end function
'This function is used to determine whether a set of points are in a
'region that has been created. The region handle is required and two
'coordinatant points. The region handle is obtained in this case from
'the array region using the value passed in the variable point as the
'array index. The call returns a zero if the point is not in a region
'and a non-zero if it is.
function regionPoint(point,X,Y)
regn=region(point)
calldll #gdi32, "PtInRegion", _
regn as long, _
X as long, _
Y as long, _
regionPoint as long
end function